﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using OpenTK.Graphics.OpenGL;
using OrionFlamesMn;

namespace OrionFlamesCSharpGui
{
	public partial class MainForm : Form
	{
		IfsAnimatorMn m_Animator;
		List<XFormGUI> m_XFormGUIs = new List<XFormGUI>();

		public MainForm()
		{
			//m_Animator = new IfsAnimatorMn();

			InitializeComponent();
			Text = "Orion Flames " + Assembly.GetExecutingAssembly().GetName().Version;
		}

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);

			renderer_Resize(this, EventArgs.Empty);   // Ensure the Viewport is set up correctly
			GL.ClearColor(Color.LightSlateGray);
		}
		
		//float rotVal = 0.0f;

		private void renderer_Paint(object sender, PaintEventArgs e)
		{
			renderer.MakeCurrent();

			GL.Clear(ClearBufferMask.ColorBufferBit);

			if (m_Animator != null)
				m_Animator.Draw(renderer.ClientSize.Width, renderer.ClientSize.Height);

			//Beyond this point nothing is drawable, as the IFS texture obscures the entire screen.
			//Need to figure out how to fix that.

			//GL.Rotate(rotVal, 0.0, 1.0, 0.0);
			//rotVal += 0.1f;

			//GL.Color3(Color.Purple);
			//GL.Begin(BeginMode.Lines);
			//GL.Vertex2(-1.0, 1.0);
			//GL.Vertex2(1.0, -1.0);
			//GL.End();

			renderer.SwapBuffers();
			renderer.Invalidate();
		}

		private void renderer_Resize(object sender, EventArgs e)
		{
			if (renderer.ClientSize.Height == 0)
				renderer.ClientSize = new System.Drawing.Size(renderer.ClientSize.Width, 1);

			GL.Viewport(0, 0, renderer.ClientSize.Width, renderer.ClientSize.Height);
		}

		private void btnIfs_Click(object sender, EventArgs e)
		{
			Init();
		}

		private void Init()
		{
			if (m_Animator == null)
				m_Animator = new IfsAnimatorMn();

			//Ensure creation was successful, then set up the GUI.
			if (m_Animator != null)
			{
				for (int i = 0; i < PresetListMn.Size(); i++)
				{
					String s = PresetListMn.Get(i).Name();
					Console.WriteLine(s);
					comboPresetList.Items.Add(s);
				}

				comboPresetList.Focus();
				comboPresetList.SelectedIndex = 0;

				//Make the rotation checkboxes reflect our default rotation bools for each axis.
				chkRotateX.Checked = m_Animator.RotateX;
				chkRotateY.Checked = m_Animator.RotateY;
				chkRotateO.Checked = m_Animator.RotateO;
			}
		}

		private void NextPreset(uint index)
		{
			m_Animator.NextPreset(index, false);
			renderer.Refresh();//Perform at least one frame update, then update the GUI below to reflect what we've got.
			//Wait until it actually processes the request to change the preset.
			//while (m_Animator.CurrentPresetIndex() != index) { }
				//Thread.Sleep(1);

			trkExposure.Value = (int)(m_Animator.Exposure * 100.0);
			trkColor.Value = (int)(m_Animator.Colorful * 100.0);
			trkTexScale.Value = (int)(m_Animator.TexScale * 100.0);
			trkScreenInitScale.Value = (int)m_Animator.ScreenInitScale;
			trkFirstLevel.Value = m_Animator.FirstLevel;
			trkLastLevel.Value = m_Animator.LastLevel;
			trkIterations.Value = m_Animator.Iterations;
			trkXRotSpeed.Value = (int)(m_Animator.XRotationRate * (float)trkXRotSpeed.Maximum);
			trkYRotSpeed.Value = (int)(m_Animator.YRotationRate * (float)trkYRotSpeed.Maximum);
			trkORotSpeed.Value = (int)(m_Animator.ORotationRate * (float)trkORotSpeed.Maximum);

			//Fill XForm panel.
			PresetMn preset = m_Animator.CurrentPreset();
			m_XFormGUIs.Clear();
			pnlXForms.Controls.Clear();

			for (uint i = 0; i < preset.Size(); i++)
			{
				XFormGUI xformGUI = new XFormGUI(preset.GetXForm(i), m_Animator, i, grpPresetParams.Width);
				m_XFormGUIs.Add(xformGUI);
				pnlXForms.Controls.Add(xformGUI.GroupBox);
			}

			//Reposition the group boxes so they are all visible.
			for (int i = 0; i < m_XFormGUIs.Count(); i++)
			{
				int offset = 8;
				GroupBox groupBox = m_XFormGUIs[i].GroupBox;

				if (i == 0)
				{
					groupBox.Top = offset;
				}
				else
				{
					GroupBox previousGroupBox = m_XFormGUIs[i - 1].GroupBox;
					groupBox.Top = previousGroupBox.Top + previousGroupBox.Height + offset;
				}
			}

			//Display the pixel shader text for debugging purposes.
			txtPixelShader.Text = preset.PixelShaderText();
		}

		private void comboPresetList_SelectedIndexChanged(object sender, EventArgs e)
		{
			comboPresetList.Refresh();
			NextPreset((uint)comboPresetList.SelectedIndex);
			comboPresetList.Refresh();
		}

		private void chkRotateX_CheckedChanged(object sender, EventArgs e)
		{
			m_Animator.RotateX = chkRotateX.Checked;
		}

		private void chkRotateY_CheckedChanged(object sender, EventArgs e)
		{
			m_Animator.RotateY = chkRotateY.Checked;
		}

		private void chkRotateO_CheckedChanged(object sender, EventArgs e)
		{
			m_Animator.RotateO = chkRotateO.Checked;
		}

		/// <summary>
		/// Happens when someone manually scrolls it to a position, in which
		/// case we want to change the value for the current preset.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void trkExposure_Scroll(object sender, EventArgs e)
		{
			trkExposure_ValueChanged(sender, e);
			m_Animator.Exposure = Exposure;
		}

		/// <summary>
		/// Happens when we programatically set the value, in which case we just
		/// want to show the value for the current preset.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void trkExposure_ValueChanged(object sender, EventArgs e)
		{
			lblExposureVal.Text = Exposure.ToString("F2");
		}

		private void trkColor_Scroll(object sender, EventArgs e)
		{
			trkColor_ValueChanged(sender, e);
			m_Animator.Colorful = Colorful;
		}

		private void trkColor_ValueChanged(object sender, EventArgs e)
		{
			lblColorVal.Text = Colorful.ToString("F2");
		}

		private void trkTexScale_Scroll(object sender, EventArgs e)
		{
			trkTexScale_ValueChanged(sender, e);
			m_Animator.TexScale = TexScale;
		}

		private void trkTexScale_ValueChanged(object sender, EventArgs e)
		{
			lblTexScaleVal.Text = TexScale.ToString("F2");
		}

		private void trkScreenInitScale_Scroll(object sender, EventArgs e)
		{
			trkScreenInitScale_ValueChanged(sender, e);
			m_Animator.ScreenInitScale = ScreenInitScale;
		}

		private void trkScreenInitScale_ValueChanged(object sender, EventArgs e)
		{
			lblScreenInitScaleVal.Text = ((int)ScreenInitScale).ToString();
		}

		private void trkFirstLevel_Scroll(object sender, EventArgs e)
		{
			trkFirstLevel_ValueChanged(sender, e);
			m_Animator.FirstLevel = FirstLevel;
		}

		private void trkFirstLevel_ValueChanged(object sender, EventArgs e)
		{
			lblFirstLevelVal.Text = FirstLevel.ToString();
		}

		private void trkLastLevel_Scroll(object sender, EventArgs e)
		{
			trkLastLevel_ValueChanged(sender, e);
			m_Animator.LastLevel = LastLevel;
		}

		private void trkLastLevel_ValueChanged(object sender, EventArgs e)
		{
			lblLastLevelVal.Text = LastLevel.ToString();
		}

		private void trkIterations_Scroll(object sender, EventArgs e)
		{
			trkIterations_ValueChanged(sender, e);
			m_Animator.Iterations = Iterations;
		}

		private void trkIterations_ValueChanged(object sender, EventArgs e)
		{
			lblIterationsVal.Text = Iterations.ToString();
		}

		float XRot
		{
			get { return (float)((float)trkXRotSpeed.Value / (float)(trkXRotSpeed.Maximum)); }
		}

		float YRot
		{
			get { return (float)((float)trkYRotSpeed.Value / (float)(trkYRotSpeed.Maximum)); }
		}

		float ORot
		{
			get { return (float)((float)trkORotSpeed.Value / (float)(trkORotSpeed.Maximum)); }
		}

		//Maybe add setters to these?
		float Exposure
		{
			get { return (float)(trkExposure.Value / 100.0); }
		}

		float Colorful
		{
			get { return (float)(trkColor.Value / 100.0); }
		}

		float TexScale
		{
			get { return (float)(trkTexScale.Value / 100.0); }
		}

		float ScreenInitScale
		{
			get { return (float)(trkScreenInitScale.Value); }
		}

		int FirstLevel
		{
			get { return trkFirstLevel.Value; }
		}

		int LastLevel
		{
			get { return trkLastLevel.Value; }
		}

		int Iterations
		{
			get { return trkIterations.Value; }
		}

		private void trkXRotSpeed_Scroll(object sender, EventArgs e)
		{
			m_Animator.XRotationRate = XRot;
			trkXRotSpeed_ValueChanged(sender, e);

			//Scroll them all.
			if ((Control.ModifierKeys & Keys.Control) != 0)
			{
				trkYRotSpeed.Value = trkORotSpeed.Value = trkXRotSpeed.Value;
				trkYRotSpeed_Scroll(sender, e);//Ridiculous that we have to manually call these.
				trkORotSpeed_Scroll(sender, e);
			}
		}

		private void trkXRotSpeed_ValueChanged(object sender, EventArgs e)
		{
			lblXRotVal.Text = m_Animator.XRotationRate.ToString("F2");
		}

		private void trkYRotSpeed_Scroll(object sender, EventArgs e)
		{
			m_Animator.YRotationRate = YRot;
			trkYRotSpeed_ValueChanged(sender, e);
		}

		private void trkYRotSpeed_ValueChanged(object sender, EventArgs e)
		{
			lblYRotVal.Text = m_Animator.YRotationRate.ToString("F2");
		}

		private void trkORotSpeed_Scroll(object sender, EventArgs e)
		{
			m_Animator.ORotationRate = ORot;
			trkORotSpeed_ValueChanged(sender, e);
		}

		private void trkORotSpeed_ValueChanged(object sender, EventArgs e)
		{
			lblORotVal.Text = m_Animator.ORotationRate.ToString("F2");
		}
	}
}
